#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include "Sem.hpp"

namespace RingBufferModule
{
    template <class T>
    class RingBuffer
    {
    private:
        // 数组模拟环形队列
        std::vector<T> _ring;
        // 容量
        int _cap;
        // 生产/消费下标
        int _productor_step;
        int _consumer_step;
        // 信号量
        Sem _room_sem; // 空间 - 生产者相关
        Sem _data_sem; // 数据 - 消费者相关
        // 锁
        pthread_mutex_t _productor_mutex;
        pthread_mutex_t _consumer_mutex;

        void Lock(pthread_mutex_t &mutex)
        {
            pthread_mutex_lock(&mutex);
        }
        void Unlock(pthread_mutex_t &mutex)
        {
            pthread_mutex_unlock(&mutex);
        }

    public:
        RingBuffer(int cap)
            : _cap(cap), _ring(cap), _productor_step(0), _consumer_step(0), _room_sem(cap), _data_sem(0)
        {
        }
        ~RingBuffer()
        {
        }
        void Enqueue(const T &in)
        {
            //申请空间信号量
            _room_sem.P();
            pthread_mutex_lock(&_productor_mutex);
            _ring[_productor_step++] = in;
            _productor_step %= _cap;
            pthread_mutex_unlock(&_productor_mutex);
            _data_sem.V();
            //释放数据信号量
        }
        void Pop(T *out)
        {
            //申请数据信号量
            _data_sem.P();
            pthread_mutex_lock(&_consumer_mutex);
            *out = _ring[_consumer_step++];
            _consumer_step %= _cap;
            pthread_mutex_unlock(&_consumer_mutex);
            _room_sem.V();
            //释放空间信号量
        }
    };
}
